package com.jm3.riscar3.core;

import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.HashMap;

import com.jm3.riscar3.exceptions.BitStringException;
import com.jm3.riscar3.exceptions.IOPortAddressingException;
import com.jm3.riscar3.exceptions.OutOfBoundsMemoryLocationException;
import com.jm3.riscar3.helpers.BinaryTranslator;
import com.jm3.riscar3.helpers.StringToBinaryTranslator;
import com.jm3.riscar3.interfaces.IAR3Command;
import com.jm3.riscar3.commands.*;
import com.jm3.riscar3.alu.*;
public class CoreManager {
	private Microcontroller mcu;
	private final int INSTRUCTION_LOCATIONS=128;
	private HashMap<String, IAR3Command> commands;
	public CoreManager(Microcontroller mcu){
		this.mcu=mcu;
		commands = new HashMap<String, IAR3Command>();

		// ALU Commands
		commands.put("00000", new AND(mcu));
		commands.put("00001", new OR(mcu));
		commands.put("00010", new XOR(mcu));
		commands.put("00011", new ADDC(mcu));
		commands.put("00100", new SUB(mcu));
		commands.put("00101", new MUL(mcu));
		commands.put("00110", new NEG(mcu));
		commands.put("00111", new NOT(mcu));
		commands.put("01000", new RLC(mcu));
		commands.put("01001", new RRC(mcu));

		// Data Transfer
		commands.put("01010", new LDArf(mcu));
		commands.put("01011", new STArf(mcu));
		commands.put("01100", new LDAaddr(mcu));
		commands.put("01101", new STAaddr(mcu));
		commands.put("01110", new LDIimmediate(mcu));

		// Control Flow
		commands.put("10000", new BRZ(mcu));
		commands.put("10001", new BRC(mcu));
		commands.put("10010", new BRN(mcu));
		commands.put("10011", new BRO(mcu));
		commands.put("11111", new STOP(mcu));
		commands.put("11000", new NOP(mcu));
	}
	public void step()throws IOPortAddressingException, Exception{
		try{
			int memLoc = mcu.getCPU().getPC().readRegister();
			mcu.getCPU().getPC().writeRegister(memLoc+2);
			String instruction = BinaryTranslator.getBitStringFromInt(mcu.getMemory().readLocation(memLoc),8);
			instruction += BinaryTranslator.getBitStringFromInt(mcu.getMemory().readLocation(memLoc+1),8);
			mcu.getCPU().getIR().writeRegister(BinaryTranslator.getBitValue(instruction));
			findCommand();
		}catch(OutOfBoundsMemoryLocationException e){}
		catch(BitStringException e){}
	}
	private void findCommand() throws Exception, IOPortAddressingException {
		// ArrayList<IAR3Command> commands = new ArrayList<IAR3Command>();
		String opcode = BinaryTranslator.getBitStringFromInt(
				mcu.getCPU().getIR().readRegister(), 16).substring(0, 5);
		String args = BinaryTranslator.getBitStringFromInt(
				mcu.getCPU().getIR().readRegister(), 16).substring(5);

		IAR3Command cmd = commands.get(opcode);
		
			cmd.execute(args);
		
		
	}
	public void read(File file) {
		
		try{
			FileReader input = new FileReader(file);
			int str =input.read();
			String tmpstr="";
			char val = (char) str;
			tmpstr+=val;
			int memLoc=0;
			int index=1;
			int data=0;
			while(str!=-1){
				str=input.read();
				val = (char) str;
				if(index==2){
					data=StringToBinaryTranslator.HexToByte(tmpstr);
					mcu.getMemory().writeToLocation(memLoc++, data);
					index=0;
					tmpstr="";
				}
				if(str==13 || str==10){}
				else{
					index++;
					tmpstr+=val;
				}
				
			}
		}
		catch(Exception e){
			System.out.print("File Read ERROR!");
		}
		
	}
	public int getINSTRUCTION_LOCATIONS() {
		return INSTRUCTION_LOCATIONS;
	}
}
